# interviews.tcl 1.1
#
# An interview system
#
# Author: CrazyCat <crazycat@c-p-f.org>
# http://www.eggdrop.fr
# irc.zeolia.net #eggdrop

## DESCRIPTION ##
#
# This TCL is a way to make interviews with a moderation channel
#
# Actually, no protection exists for the moderation channel
# The moderator has to manage it himself (invite only, key, ...)
# The eggdrop must be at least halfop on the itw channel

## USAGE ##
# * In moderation channel
# - .itw : shows the help (!itw works too)
# - .itstart [nick] : Starts the interview, nick is the speaker
#   if no nick is given, the moderator is the speaker
#   The moderator is the personn who typed .itstart
# - .itstop : Stops the interview. Only speaker and moderator
#   can do that
# - .no : Rejects the current question
# - .yes : Accepts the current question (displays it in the
#   interview channel)
# * By message
# - !quest <Your question> : Adds a question to the queue

## CHANGELOG ##
# Version 1.1
# - Addition of +u mode
# - Multilingual version
# Version 1.0
# - Initial release

## TODO ##
# - Adding protections
# - Manage users with the eggdrop userlist

## CONFIGURATION ##

namespace eval itw {
	
	# the main channel
	set chan(itw) "#interviews"
	
	# the moderation channel
	set chan(mod) "#redaction"
	
   # Minimal number of chars in a question
	variable minchars 10
	
	# Logfile
	variable logpath "logs/"
	variable recorder "interview.txt"

   # Extra mode : +N (no nick change in channel)
   # Set to 0 to not use it
   variable useN 1
   # Extra mode : +u (auditorium, hides join/part/quit)
   # Set to 0 to not use it
   variable useu 1
}

################################
# Do not edit anything below ! #
################################

namespace eval itw {
   package require msgcat
    	
   variable queue
   set crnt 0
   set disp 0

   variable author "CrazyCat"
   variable version "1.1"
   variable speaker
   variable moderator

   # Here we define the different messages
   ::msgcat::mcset fr errnoc1 "Vous n'êtes pas sur %s"
   ::msgcat::mcset fr errnoc2 "%s n'est pas sur %s"
   ::msgcat::mcset fr errnoc3 "Vous ne pouvez pas poser de question"
   ::msgcat::mcset fr errquest1 "Merci de poser une question d'au moins %d caractères"
   ::msgcat::mcset fr errstop "Vous ne pouvez pas arrêter l'interview"
   ::msgcat::mcset fr start1 "Démarrage de l'interview de %s"
   ::msgcat::mcset fr start2 "Pour poser une question, tapez \002/msg %s !quest \037Texte de votre question\037\002"
   ::msgcat::mcset fr startlog "--- Démarrage de l'interview de %s le %s ---"
   ::msgcat::mcset fr end1 "Fin de l'interview de %s"
   ::msgcat::mcset fr endlog "--- Fin l'interview de %s le %s ---"
   ::msgcat::mcset fr qmod "Question N°%d de \002%s\002 : "
   ::msgcat::mcset fr errlng1 "%s n'est pas une langue actuellement disponible"
   ::msgcat::mcset fr errlng2 "Faites votre choix parmi: \002%s\002"
   ::msgcat::mcset fr lngchd "Langue définie: %s"

   ::msgcat::mcset en errnoc1 "You are not on %s"
   ::msgcat::mcset en errnoc2 "%s is not on %s"
   ::msgcat::mcset en errnoc3 "You can not ask a question"
   ::msgcat::mcset en errquest1 "Your question must contains %d characters at least"
   ::msgcat::mcset en errstop "You can not stop the interview"
   ::msgcat::mcset en start1 "Start of the interview of %s"
   ::msgcat::mcset en start2 "To ask a question, type \002/msg %s !quest \037Your question\037\002"
   ::msgcat::mcset en startlog "--- Start of interview of %s on %s ---"
   ::msgcat::mcset en end1 "End of the interview of %s"
   ::msgcat::mcset en endlog "--- End of the interview of %s on %s ---"
   ::msgcat::mcset en qmod "Quest #%d from \002%s\002 : "
   ::msgcat::mcset en errlng1 "%s is currently not available"
   ::msgcat::mcset en errlng2 "Choose the language among \002%s\002"
   ::msgcat::mcset en lngchd "Language defined: %s"
   
   # Help messages
   ::msgcat::mcset fr help01 "Aide pour Interview V%s"
   ::msgcat::mcset fr help02 "Commandes dans le canal de modération"
   ::msgcat::mcset fr help03 ".itw : affiche cet aide (!itw est aussi possible)"
   ::msgcat::mcset fr help04 ".itstart \[nick\] : Démarre l'interview avec nick comme invité."
   ::msgcat::mcset fr help05 "   (si aucun nick n'est donné, le modérateur est l'invité. Le modérateur est celui qui lance l'interview)"
   ::msgcat::mcset fr help06 ".itstop : Arrête l'interview. Seuls l'invité et le modérateur peuvent utiliser cette commande"
   ::msgcat::mcset fr help07 ".no : Rejette la question actuelle"
   ::msgcat::mcset fr help08 ".yes : Accepte la question actuelle (l'affiche dans le canal publique)"
   ::msgcat::mcset fr help09 ".itwlng <%s> : Change la langue de l'interview (seulement lorsqu'aucune interview n'est en cours)"
   ::msgcat::mcset fr help10 "Commandes par message"
   ::msgcat::mcset fr help11 "!quest <Votre question> : Ajoute une question à la file d'attente"
                                 
   ::msgcat::mcset en help01 "Help for Interview V%s"
   ::msgcat::mcset en help02 "Commands in moderation channel"
   ::msgcat::mcset en help03 ".itw : shows the help (!itw works too)"
   ::msgcat::mcset en help04 ".itstart \[nick\] : Starts the interview, nick is the speaker."
   ::msgcat::mcset en help05 "   (if no nick is given, the moderator is the speaker, the moderator is the personn who typed .itstart)"
   ::msgcat::mcset en help06 ".itstop : Stops the interview. Only speaker and moderator can do that"
   ::msgcat::mcset en help07 ".no : Rejects the current question"
   ::msgcat::mcset en help08 ".yes : Accepts the current question (displays it in the interview channel)"
   ::msgcat::mcset en help09 ".itwlng <%s> : Changes the itw language (only when no interview in progress"
   ::msgcat::mcset en help10 "Commands by message"
   ::msgcat::mcset en help11 "!quest <Your question> : Adds a question to the queue"
   
   set langs { fr en }
   setudef str itwlang
   
   # Script initialisation
   proc init {} {
      if {![validchan [string tolower $::itw::chan(mod)]]} {
          channel add [string tolower $::itw::chan(mod)]
      }
      if {![validchan [string tolower $::itw::chan(itw)]]} {
         channel add [string tolower $::itw::chan(itw)]
      }
      bind pub - ".itw" [namespace current]::help
      bind pub - "!itw" [namespace current]::help
      bind evnt -|- prerehash [namespace current]::deinit
      bind pub - ".itwlng" [namespace current]::setlang
      if {[channel get $::itw::chan(mod) itwlang]==""} {
         channel set $::itw::chan(mod) itwlang "fr"
      }
      ::msgcat::mclocale [channel get $::itw::chan(mod) itwlang]
      putlog "Interviews V$::itw::version by $::itw::author loaded"
   }

   proc setlang {nick uhost handle chan args} {
      if { [string tolower $chan] != [string tolower $::itw::chan(mod)] } {
         return 0;
      }
      if { [lsearch $::itw::langs [lindex [split $args] 0]] == -1 } {
         putserv "PRIVMSG $::itw::chan(mod) :[::msgcat::mc errlng1 [lindex [split $args] 0]]"
         putserv "PRIVMSG $::itw::chan(mod) :[::msgcat::mc errlng2 [join $::itw::langs]]"
         return 0;
      }
      channel set $::itw::chan(mod) itwlang [lindex [split $args] 0]
      ::msgcat::mclocale [channel get $::itw::chan(mod) itwlang]
      putserv "PRIVMSG $::itw::chan(mod) :[::msgcat::mc lngchd [::msgcat::mclocale]]"
   }

	# Pre-rehash : clearing namespace
   proc deinit {type} {
      foreach child [namespace children] {
         catch {[set child]::deinit $type}
      }
      putlog "Interviews $::itw::version unloaded"
      namespace delete [namespace current]
   }

   # Starting the interview
   bind pub - ".itstart" [namespace current]::itwstart
   proc itwstart {nick uhost handle chan text} {
      # Verifications:
      # - user must start in moderation channel
      # - user must be present in itw channel
      if {[string tolower $chan] != [string tolower $::itw::chan(mod)] } { return 0; }
      if {![onchan $nick $::itw::chan(itw)] } {
         putserv "PRIVMSG $::itw::chan(mod) :[::msgcat::mc errnoc1 $::itw::chan(itw)]"
         return 0
      }
      # Roles assignation
      set [namespace current]::moderator $nick
      set vict [join [lindex [split $text] 0]]
      if { $vict == "" } {
         set [namespace current]::speaker $nick
      } else {
         if {![onchan $vict $::itw::chan(itw)] } {
            putserv "PRIVMSG $::itw::chan(mod) :[::msgcat::mc errnoc2 $vict $::itw::chan(itw)]"
            unset [namespace current]::moderator
            return 0
         }
         set [namespace current]::speaker $vict
      }
      
      unbind pub - ".itwlng" [namespace current]::setlang
      
      set ::itw::crnt 0
      set ::itw::disp 0
      
      # setting modes on channel
      pushmode $::itw::chan(itw) +m
      pushmode $::itw::chan(itw) +o $::itw::moderator
      pushmode $::itw::chan(itw) +v $::itw::speaker
      if {$::itw::useN eq 1} {
         pushmode $::itw::chan(itw) +N
      }
      if {$::itw::useu eq 1} {
         pushmode $::itw::chan(itw) +u
      }
      flushmode $::itw::chan(itw)
      bind pub - ".itstop" [namespace current]::itwstop
      bind msg - "!quest" [namespace current]::newquest
      bind pub - ".no" [namespace current]::reject
      bind pub - ".yes" [namespace current]::accept
      unbind pub - ".itstart" [namespace current]::itwstart
      bind pubm - "$::itw::chan(itw) *" [namespace current]::answer
      putserv "PRIVMSG $::itw::chan(itw) :[::msgcat::mc start1 $::itw::speaker]"
      putserv "PRIVMSG $::itw::chan(itw) :[::msgcat::mc start2 $::botnick]"
      ::itw::newfile
      [namespace current]::log [::msgcat::mc startlog $::itw::speaker "[strftime %D\ %T]"]
      return 1
   }
   
   # Adding question to queue
   proc newquest {nick uhost handle text} {
      if { ![onchan $nick $::itw::chan(itw)] } {
         putserv "PRIVMSG $nick :[::msgcat::mc errnoc3]"
         return 0
      }
      set text [stripcodes abcgru $text]
      if {[string length $text]<$::itw::minchars} {
         putserv "PRIVMSG $nick :[::msgcat::mc errquest1 $::itw::minchars]
         return 0
      }
      lappend ::itw::queue "$nick#$text"
      if { $::itw::crnt eq $::itw::disp } {
         [namespace current]::nextquest
      }
   }
   
   # Displays the next question in the moderation channel
   proc nextquest {} {
      if { ($::itw::crnt+1) > [llength $::itw::queue] } {
         # Bypass if another question is already pending
         return
      }
      incr ::itw::crnt
      set quest [lindex $::itw::queue $::itw::crnt-1]
      set auth [lindex [split $quest "#"] 0]
      set quest [join [lindex [split $quest "#"] 1]]
      putserv "PRIVMSG $::itw::chan(mod) :[::msgcat::mc qmod $::itw::crnt $auth]$quest"
   }
   
   # Rejection
   proc reject {nick uhost handle chan text} {
	  set ind $::itw::disp+1
	  if { [llength $::itw::queue] < $ind } {
		  return
	  }
      incr ::itw::disp
      [namespace current]::nextquest
   }
   
   # Acceptation : Display question in itw channel
   proc accept {nick uhost handle chan text} {
	  set ind $::itw::disp+1
	  if { [llength $::itw::queue] < $ind } {
		  return
	  }
      set quest [lindex $::itw::queue $::itw::disp]
      set auth [lindex [split $quest "#"] 0]
      set quest [join [lindex [split $quest "#"] 1]]
      putserv "PRIVMSG $::itw::chan(itw) :\002$auth\002 : $quest"
      incr ::itw::disp
      [namespace current]::log "<$auth> $quest"
      [namespace current]::nextquest
   }
   
   # Just used to log the itw channel
   proc answer {nick uhost handle chan text} {
      [namespace current]::log "<$nick> $text"
   }
   
   # Stopping the interview
   proc itwstop {nick uhost handle chan text} {
      if {[string tolower $chan] != [string tolower $::itw::chan(mod)] } { return 0; }
      # NB: only speaker and moderator can stop the interview
      if {($nick != $::itw::moderator) && ($nick != $::itw::speaker)} {
         putserv "PRIVMSG $::itw::chan(mod) :[::msgcat::mc errstop]"
         return 0
      }
      unbind pubm - "$::itw::chan(itw) *" [namespace current]::answer
      unbind pub - ".no" [namespace current]::reject
      unbind pub - ".yes" [namespace current]::accept
      putserv "PRIVMSG $::itw::chan(itw) :[::msgcat::mc end1 $::itw::speaker]"
      [namespace current]::log [::msgcat::mc endlog $::itw::speaker "[strftime %D\ %T]"]
      pushmode $::itw::chan(itw) -m
      if {$::itw::useN eq 1} {
         pushmode $::itw::chan(itw) -N
      }
      if {$::itw::useu eq 1} {
         pushmode $::itw::chan(itw) -u
      }
      unbind msg - "!quest" [namespace current]::newquest
      unbind pub - ".itstop" [namespace current]::itwstop
      bind pub - ".itstart" [namespace current]::itwstart
      bind pub - ".itwlng" [namespace current]::setlang
      [namespace current]::archive
      unset ::itw::queue
      return 1
   }
   
   # Logging into a temp file
   proc log {text} {
      set text [stripcodes abcgru $text]
      set fp [open $::itw::logfile "a"]
      puts $fp [join [split $text]]
      close $fp
   }

   # Creating an empty temp file 
   proc newfile {} {
      variable logfile "$::itw::logpath$::itw::recorder"
      set fp [open $::itw::logfile "w"]
      close $fp
   }
   
   # Archiving the temp file
   proc archive {} {
      append nf $::itw::logpath "itw_[strftime %Y%m%d%H%M%S].log"
      putlog "Archiving to $nf"
      file copy $::itw::logfile $nf
   }

   # Help display procedure
   proc help {nick uhost handle chan text} {
      puthelp "PRIVMSG $chan :[::msgcat::mc help01 $::itw::version]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help02]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help03]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help04]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help05]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help06]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help07]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help08]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help09 [join $::itw::langs |]]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help10]"
      puthelp "PRIVMSG $chan :[::msgcat::mc help11]"
   }
}

# Start initialisation
::itw::init

